#pragma once

#include "sock.hpp"
#include <string>
#include <functional>
#include <sys/epoll.h>

const static int defaultNum = 128;

typedef std::function<std::string(const std::string &)> func_t;
// using func_t = std::function<std::string(const std::string &)>;

class Server
{
public:
    Server(uint16_t port, func_t func, int num = defaultNum)
        : _listenSock(-1), _port(port), _num(num), _epfd(-1), _readyEv(nullptr), _func(func)
    {
    }

    void initServer()
    {
        // 1.创建监听套接字
        _listenSock = Sock::Socket();
        Sock::Bind(_listenSock, _port);
        Sock::Listen(_listenSock);

        // 2.创建epoll模型
        _epfd = epoll_create(_num);
        if (_epfd < 0)
        {
            logMessage(FATAL, "epoll模型创建失败");
            exit(EPOLL_CREATE);
        }
        // 3.将监听套接字托管给epoll
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _listenSock;
        epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenSock, &ev);

        // 4.给返回的就绪事件申请空间，该数组大小要小于等于epoll_create传入的参数
        _readyEv = new struct epoll_event[_num];
    }

    void Recv(int sock)
    {
        char buf[1024];
        // 这里简化了，直接认为接收到的是一条完整的报文
        //  1.读取数据
        int n = recv(sock, buf, sizeof(buf) - 1, 0);
        if (n > 0)
        {
            buf[n] = 0;
            std::cout << "客户端#" << buf << std::endl;

            // 2.处理数据
            std::string response = _func(buf);

            // 3.发送响应
            send(sock, response.c_str(), response.size(), 0);
        }
        else if (n == 0) // 客户端退出
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr); // 先将fd从epoll中删除，再关闭
            close(sock);
            logMessage(NORMAL, "客户端退出");
        }
        else // 读取出错
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr); // 先将fd从epoll中删除，再关闭
            close(sock);
            logMessage(ERROR, "读取错误，%d: %s", errno, strerror(errno));
        }
    }

    void handlerEvent(int readyNum)
    {
        logMessage(DEBUG, "进入handlerEvent");
        for (int i = 0; i < readyNum; i++)
        {
            int sock = _readyEv[i].data.fd;       // 就绪的fd
            uint32_t events = _readyEv[i].events; // 该fd就绪的事件

            if (sock == _listenSock && events & EPOLLIN) //_listenSock就绪
            {
                std::string clientIp;
                uint16_t clientPort;
                int sock = Sock::Accept(_listenSock, &clientIp, &clientPort);
                if (sock < 0)
                {
                    continue; // 连接失败，继续for循环，处理其他就绪时间。错误信息在Sock::Acceept中打印了
                }
                // 将新的文件描述符托管给epoll
                struct epoll_event ev;
                ev.events = EPOLLIN;
                ev.data.fd = sock;
                epoll_ctl(_epfd, EPOLL_CTL_ADD, sock, &ev);
            }
            else if (events & EPOLLIN) // 普通的读就绪
            {
                Recv(sock); // 读取
            }
            else if (events & EPOLLOUT) // 写事件就绪
            {
                // 写入
            }
            else
            {
            }
        }
        logMessage(DEBUG, "退出handlerEvent");
    }

    void start()
    {
        for (;;)
        {
            int timeout = 0;
            int n = epoll_wait(_epfd, _readyEv, _num, timeout);
            switch (n)
            {
            case 0:
                // logMessage(NORMAL,"超时退出");
                break;
            case -1:
                logMessage(ERROR, "epoll_wait 出错");
                break;
            default:
            {
                logMessage(NORMAL, "有事件就绪");
                handlerEvent(n);
            }
            break;
            }
        }
    }

    ~Server()
    {
        if (_listenSock != -1)
            close(_listenSock);
        if (_epfd != -1)
            close(_epfd);
        if (_readyEv)
            delete[] _readyEv;
    }

private:
    int _listenSock;
    int _port;
    int _num;
    int _epfd;
    struct epoll_event *_readyEv;
    func_t _func;
};
